using System;
using System.Linq.Expressions;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using WatiN.Core;

namespace FluentWatin
{
    public class ControllerProxy<CONTROLLERTYPE> where CONTROLLERTYPE : class
    {
        public Browser browser;

        private string baseUrl = "http://localhost/";

        public ControllerProxy(Browser browser)
        {
            this.browser = browser;
        }
        public ControllerProxy(Browser browser,string baseUrl)
        {
            this.baseUrl = baseUrl;
            this.browser = browser;
        }
        private string BuildUrlFromControllerAction(string actionName)
        {
            string controllerUrl = typeof(CONTROLLERTYPE).Name.Replace("Controller", "");

            return baseUrl + controllerUrl + "/" + actionName;
        }

        public ControllerProxy<CONTROLLERTYPE> ExecuteAction(Expression<Func<CONTROLLERTYPE, Object>> expression)
        {
            var methodCall = (MethodCallExpression)expression.Body;
            var url = BuildUrlFromControllerAction(methodCall.Method.Name);

            foreach (var argument in methodCall.Arguments)
                url += "/" + argument;

            browser.GoTo(url);

            return this;
        }

        public ControllerProxy<CONTROLLERTYPE> SubmitForm<FORMDATATYPE>(Action<FORMDATATYPE> action) where FORMDATATYPE : new()
        {
            var administrationActions = new FORMDATATYPE();

            action(administrationActions);

            foreach (var property in administrationActions.GetType().GetProperties())
            {
                var value = property.GetValue(administrationActions, null);

                SetValue(property.Name, value.ToString());

            }

            browser.Forms[0].Submit();


            return this;
        }

        private void SetValue(string id, string value)
        {
            var input = browser.TextField(id);
            if (input != null)
            {
                input.Value = value;
                return;
            }
            
            //todo add support for more elements
        }

     

        public void AssertViewData<TViewModel>(Func<TViewModel, bool> func) where TViewModel : new()
        {
            var viewModel = HydrateFromBrowser<TViewModel>();

            Assert.That(func(viewModel), Is.True);
        }

        private TViewModel HydrateFromBrowser<TViewModel>() where TViewModel : new()
        {
            var hydratedObject = new TViewModel();

            foreach (var property in hydratedObject.GetType().GetProperties())
            {
                var valueFromBrowser = browser.Element(property.Name).Text;
                property.SetValue(hydratedObject, valueFromBrowser, null);
            }
            return hydratedObject;
        }
    }
}